﻿using Ducu.BLL.Entity;
using Ducu.GLB.Global;
using Ducu.SRV.ServiceInteface;
using Ducu.SRV.ViewModel.Task.Shared;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ducu.SRV.Query;
using Ducu.SRV.ViewModel.Task;
using AutoMapper;
using Ducu.SRV.ViewModel.Shared;
using Global.Core.ExtensionMethod;

namespace Ducu.SRV.ProdService
{
    public class TaskService : BaseService, ITaskService
    {
        public FulfilModel GetFulfil(int planId)
        {
            FulfilModel model = new FulfilModel
            {
                WeekDays = GetWeekChart(planId)
            };
            model.NeedFulfil = model.WeekDays
                .Where(w => w.Status == Status.WaitComplete).Count() > 0;
            return model;
        }

        public void Fulfil(FulfilModel model, int planId)
        {
            PlanService planService = new PlanService();
            if (planService.IsCurrentUserVower(planId))
            {
                Task task = Mapper.Map<Task>(model.TaskItem);
                task.Plan = repoFactory.Load<Plan>(planId);

                HistoryItem history = new HistoryItem
                {
                    MyComment = model.TaskItem.Comment,
                    Status = Status.WaitAccept,
                    Task = task,
                    Executor = task.Plan.Vower
                };
                history.Build();

                repoFactory.Save<Task>(task);
            }
        }

        public IList<_TaskItemModel> GetNeedAccept()
        {
            User current = getCurrentUser();
            var tasks = repoFactory.Query<Task>().GetNeedAccepted(current);
            return Mapper.Map<IList<_TaskItemModel>>(tasks.ToList());
        }

        public IList<_TaskItemModel> GetNeedAccept(int planId)
        {
            User current = getCurrentUser();
            var tasks = repoFactory.Query<Task>().GetNeedAccepted(current, planId);
            return Mapper.Map<IList<_TaskItemModel>>(tasks.ToList());
        }

        public _TaskItemModel Get(int taskId)
        {
            Task task = repoFactory.Load<Task>(taskId);
            return Mapper.Map<_TaskItemModel>(task);
        }

        internal IList<_DayModel> getPrevious(Plan plan, int days)
        {
            IList<_DayModel> models = new List<_DayModel>();

            DateTime now = DateTime.Now;
            for (int i = days; i >= 0; i--)
            {
                _DayModel model = getDayModel(plan, now.AddDays(-1 * i).Date);
                models.Add(model);
            }

            return models;
        }

        private _DayModel getDayModel(Plan plan, DateTime complete)
        {
            _DayModel model = new _DayModel();
            model.CompleteDate = complete;

            if (complete < plan.From || complete > plan.To)
            {
                model.Status = Status.Empty;
            }
            else if (plan.Rest(model.CompleteDate))
            {
                model.Status = Status.Rest;
            }
            else
            {
                Task task = repoFactory.Query<Task>()
                    .GetByDate(model.CompleteDate, plan).SingleOrDefault();
                if (task == null)
                {
                    model.Status = plan.CanComplete(model.CompleteDate);
                }
                else
                {
                    model.Status = task.Status;
                    model.Id = task.Id;
                }
            }

            //TODO: there is a little performace issue, but ?
            //Task task = repoFactory.Query<Task>()
            //    .GetByDate(model.Date, plan).SingleOrDefault();
            //model.Status = plan.Check(task);

            return model;
        }

        public IList<_DayModel> GetWeekChart(int planId)
        {
            Plan plan = repoFactory.Load<Plan>(planId);

            int days = 6;

            return getPrevious(plan, days);
        }

        public void DoAccept(AcceptModel model)
        {
            HistoryItem accept = Mapper.Map<HistoryItem>(model);

            accept.Executor = getCurrentUser();
            accept.Task = repoFactory.Load<Task>(model.Current.Id);
            accept.Accept();

            repoFactory.Save<HistoryItem>(accept);
        }

        public HistoryListModel GetHistoryList(int planId, Pager pager)
        {
            Plan plan = repoFactory.Load<Plan>(planId);
            var tasks = repoFactory.Query<Task>().GetByPlan(plan)
                .OrderByDescending(t => t.CompleteDate)
                .Page(pager);
            HistoryListModel model = new HistoryListModel
            {
                Items = new List<HistoryListItemModel>()
            };
            foreach (var task in tasks)
            {
                model.Items.Add(getFrom(task));
            }
            return model;
        }



        public int GetCount(int planId)
        {
            Plan plan = repoFactory.Load<Plan>(planId);
            return repoFactory.Query<Task>().GetByPlan(plan).Count();
        }


        public HistoryMonthModel GetHistoryMonth(int planId, int year, int month)
        {
            Plan plan = repoFactory.Load<Plan>(planId);

            HistoryMonthModel model = new HistoryMonthModel
            {
                PlanBegin = plan.From,
                PlanEnd = plan.To.Value
            };

            IList<DateTime> daysInMonth = new DateTime(year, month, 1)
                .GetCurrentMonthInWeeks();

            model.Items = new List<_DayModel>();
            foreach (var item in daysInMonth)
            {
                _DayModel day = getDayModel(plan, item);
                model.Items.Add(day);
            }

            return model;
        }


        public HistoryListItemModel GetHistoryItem(int taskId)
        {
            Task task = repoFactory.Load<Task>(taskId);
            return getFrom(task);
        }

        private HistoryListItemModel getFrom(Task task)
        {
            User current = getCurrentUser();
            return new HistoryListItemModel
            {
                TaskId = task.Id,
                PlanId = task.Plan.Id,
                ShowReply = current != null
                    && task.Plan.Vower.Id == current.Id,
                ApplyAccept = task.Status == Status.Refused
                    || task.Status == Status.Question,
                CanAccept = task.Plan.Supervisors.
                    SingleOrDefault(s => s.Id == current.Id) != null,
                Title = Mapper.Map<_DayModel>(task),
                History = Mapper.Map<IList<AcceptShowItemModel>>(task.History)
            };
        }


        public void Reply(int taskId, string content, bool applyAccept)
        {
            Task task = repoFactory.Load<Task>(taskId);
            HistoryItem reply = new HistoryItem
            {
                Executor = getCurrentUser(),
                MyComment = content,
                Task = task
            };
            reply.Status = applyAccept ? Status.Resume : Status.Empty;
            reply.Reply();
        }


        public void Leave(_TaskItemModel model, int planId)
        {
            Task task = new Task 
            { 
                CompleteDate = model.CompleteDate,
                Plan = repoFactory.Load<Plan>(planId)
            };
            repoFactory.Save(task);

            HistoryItem history = new HistoryItem
            {
                Task = task,
                Executor = getCurrentUser(),
                MyComment = model.Comment,
                Status = Status.Leave
            };
            history.Leave();
        }
    }
}
